﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using RxxAdmin.Common.Helper;
using RxxAdmin.Extensions.Authorizations;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static RxxAdmin.Common.AppSettings;

namespace RxxAdmin.Extensions;

public static class Authentication_JWTSetup
{
    public static void AddAuthentication_JWTSetup(this IServiceCollection services)
    {
        if (services == null) throw new ArgumentNullException(nameof(services));
        services.AddSingleton(new JwtHelper());
        // 添加身份验证
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        // 开启Bearer认证
        services.AddAuthentication(o =>
        {
            o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        // 添加JwtBearer服务
        .AddJwtBearer(options =>
        {
            options.RequireHttpsMetadata = false;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Jwt.Issuer,
                ValidAudience = Jwt.Audience,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Jwt.SecretKey))
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    var accessToken = context.Request.Query["access_token"];

                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) &&
                        (path.StartsWithSegments("/signalr/chatHub")))
                    {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                },
                OnChallenge = context =>
                {
                    context.Response.Headers["Token-Error"] = context.ErrorDescription;
                    return Task.CompletedTask;
                },
                OnAuthenticationFailed = context =>
                {
                    var jwtHandler = new JwtSecurityTokenHandler();
                    var token = context.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");

                    if (token.IsNotEmptyOrNull() && jwtHandler.CanReadToken(token))
                    {
                        var jwtToken = jwtHandler.ReadJwtToken(token);

                        if (jwtToken.Issuer != Jwt.Issuer)
                        {
                            context.Response.Headers["Token-Error-Iss"] = "issuer is wrong!";
                        }

                        if (jwtToken.Audiences.FirstOrDefault() != Jwt.Audience)
                        {
                            context.Response.Headers["Token-Error-Aud"] = "Audience is wrong!";
                        }
                    }

                    // 如果过期，则把<是否过期>添加到，返回头信息中
                    if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                    {
                        context.Response.Headers["Token-Expired"] = "true";
                    }
                    return Task.CompletedTask;
                }
            };
        });
    }
}
